package com.ia.aistream.manager.framework.redis.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ia.aistream.manager.framework.redis.RedisHashManager;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class RedisHashManagerImpl implements RedisHashManager {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void hset(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, JSON.toJSONString(value));
    }

    @Override
    public boolean hsetnx(String key, String field, Object value) {
        return redisTemplate.opsForHash().putIfAbsent(key, field, JSON.toJSONString(value));
    }

    @Override
    public <V> V hget(String key, String field, Class<V> clazz) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(key);
        String value = operations.get(field);
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        return JSON.parseObject(value, clazz);
    }

    @Override
    public boolean hexists(String key, String field) {
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    @Override
    public void hdel(String key, Object... fields) {
        redisTemplate.opsForHash().delete(key, fields);
    }

    @Override
    public Long hlen(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    @Override
    public Long hstrlen(String key, String field) {
        return redisTemplate.opsForHash().lengthOfValue(key, field);
    }

    @Override
    public Long hincrby(String key, String field, long increment) {
        return redisTemplate.opsForHash().increment(key, field, increment);
    }

    @Override
    public Double hincrbyfloat(String key, String field, double increment) {
        return redisTemplate.opsForHash().increment(key, field, increment);
    }

    @Override
    public <V> void hmset(String key, Map<String, V> map) {
        Map<String, String> param = Maps.newHashMap();
        map.forEach((field, value) -> param.put(field, JSON.toJSONString(value)));
        redisTemplate.opsForHash().putAll(key, param);
    }

    @Override
    public <V> List<V> hmget(String key, Collection<String> fields, Class<V> clazz) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(key);
        List<String> list = operations.multiGet(fields);
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }

        List<V> result = Lists.newArrayList();
        list.forEach(element -> result.add(JSON.parseObject(element, clazz)));
        return result;
    }

    @Override
    public Set<String> hkeys(String key) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(key);
        return operations.keys();
    }

    @Override
    public <V> List<V> hvals(String key, Class<V> clazz) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(key);
        List<String> list = operations.values();
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }

        List<V> result = Lists.newArrayList();
        list.forEach(element -> result.add(JSON.parseObject(element, clazz)));
        return result;
    }

    @Override
    public <V> Map<String, V> hgetall(String key, Class<V> clazz) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(key);
        Map<String, String> map = operations.entries();
        if (org.springframework.util.CollectionUtils.isEmpty(map)) {
            return Maps.newHashMap();
        }
        Map<String, V> result = Maps.newHashMap();
        map.forEach((field, value) -> result.put(field, JSON.parseObject(value, clazz)));
        return result;
    }
}
